Monitor the update of objects with a trigger

Hello,

Maybe you could help me if next problem should be solved using a trigger: if a user changes the value of an object from a module, then an email will inform a list of users that oject id XX from module YY has been changed.
Where should be stored these triggers? Where it's stored the script? ....so that the mails should be send for each module which have saved values of objects.
Looking forward for your advices and maybe some code

Thank you in advance,
Silvius
Silvius - Sat Mar 27 17:45:00 EDT 2010

Re: Monitor the update of objects with a trigger
llandale - Sun Mar 28 18:50:30 EDT 2010

Triggers are not for the feint of heart.

If I had this chore, I'd write an on-demand script scheduled to run every night, which generates a single email and looks through all the modules of a Project looking for reportable changes in History. If scheduled for "12:01am" 00:00:01 you could look for History from 'yesterday'. Folks will appreciate a single email, and will tend to ignore the scores of individual emails they will get with the Trigger approach.

Also, the Trigger approach falls down when folks make a change, trigger an email, then do not save the module.

It is also weak in that the local user will end up sending the email, which can cause confusion and hassle.

Anway, as for the Trigger: its probably better to have the trigger deployed in the Project with smarts to know which modules to ignore. If you change the Trigger you change it on one place. Deploying it in each 'important' module makes the Trigger itself a little simpler, but its a bit of a nightmare when you want to make changes to the Trigger.

  • Louie

Re: Monitor the update of objects with a trigger
Silvius - Mon Mar 29 10:02:30 EDT 2010

llandale - Sun Mar 28 18:50:30 EDT 2010
Triggers are not for the feint of heart.

If I had this chore, I'd write an on-demand script scheduled to run every night, which generates a single email and looks through all the modules of a Project looking for reportable changes in History. If scheduled for "12:01am" 00:00:01 you could look for History from 'yesterday'. Folks will appreciate a single email, and will tend to ignore the scores of individual emails they will get with the Trigger approach.

Also, the Trigger approach falls down when folks make a change, trigger an email, then do not save the module.

It is also weak in that the local user will end up sending the email, which can cause confusion and hassle.

Anway, as for the Trigger: its probably better to have the trigger deployed in the Project with smarts to know which modules to ignore. If you change the Trigger you change it on one place. Deploying it in each 'important' module makes the Trigger itself a little simpler, but its a bit of a nightmare when you want to make changes to the Trigger.

  • Louie

Hi Louie,

Thank you for your answer.
Posting my problem here, I've thought that it can be used a trigger with a specific entity, which action at level attribute, event save. I mean that the users update the values of objects, and when they save the module, at this time the trigger fire and send mails to the users. The trigger is defined like:
trigger("trig_name", attribute->all, post , save, 1,"#include <triggers/test_trig.dxl>")
There is someone who used this kind of trigger at *attribute level*?
Can you help me with some examples?

Many thanks and looking for your answer,
Silvius

Re: Monitor the update of objects with a trigger
SystemAdmin - Mon Mar 29 10:07:58 EDT 2010

llandale - Sun Mar 28 18:50:30 EDT 2010
Triggers are not for the feint of heart.

If I had this chore, I'd write an on-demand script scheduled to run every night, which generates a single email and looks through all the modules of a Project looking for reportable changes in History. If scheduled for "12:01am" 00:00:01 you could look for History from 'yesterday'. Folks will appreciate a single email, and will tend to ignore the scores of individual emails they will get with the Trigger approach.

Also, the Trigger approach falls down when folks make a change, trigger an email, then do not save the module.

It is also weak in that the local user will end up sending the email, which can cause confusion and hassle.

Anway, as for the Trigger: its probably better to have the trigger deployed in the Project with smarts to know which modules to ignore. If you change the Trigger you change it on one place. Deploying it in each 'important' module makes the Trigger itself a little simpler, but its a bit of a nightmare when you want to make changes to the Trigger.

  • Louie

We take a different approach. Every night a job kicks off that calls a batch DXL that dumps data from modules into text files. Then we have python scripts process the text files and put the results in an SQL database. Sounds round about, but there a few advantages to doing it all in DXL:
a) We only have two people devoted to writing DXL, but a lot of software people otherwise. So all I have to do is write dump code and someone else can write the processing code.
b) Processing vast amounts of data goes much quicker in something like python or perl.
c) With the results in an SQL database, there are tons of code projects out there to convert the database to web pages.

Re: Monitor the update of objects with a trigger
mcnairk - Mon Mar 29 10:24:29 EDT 2010

SystemAdmin - Mon Mar 29 10:07:58 EDT 2010
We take a different approach. Every night a job kicks off that calls a batch DXL that dumps data from modules into text files. Then we have python scripts process the text files and put the results in an SQL database. Sounds round about, but there a few advantages to doing it all in DXL:
a) We only have two people devoted to writing DXL, but a lot of software people otherwise. So all I have to do is write dump code and someone else can write the processing code.
b) Processing vast amounts of data goes much quicker in something like python or perl.
c) With the results in an SQL database, there are tons of code projects out there to convert the database to web pages.

You have people DEVOTED to writing DXL?

Like most other people on this forum, I'd love to have that luxury! This is a part time job for me; my "real" job is managing a test team :-(

Re: Monitor the update of objects with a trigger
llandale - Mon Mar 29 15:04:24 EDT 2010

Silvius - Mon Mar 29 10:02:30 EDT 2010
Hi Louie,

Thank you for your answer.
Posting my problem here, I've thought that it can be used a trigger with a specific entity, which action at level attribute, event save. I mean that the users update the values of objects, and when they save the module, at this time the trigger fire and send mails to the users. The trigger is defined like:
trigger("trig_name", attribute->all, post , save, 1,"#include <triggers/test_trig.dxl>")
There is someone who used this kind of trigger at *attribute level*?
Can you help me with some examples?

Many thanks and looking for your answer,
Silvius

Look in the DXL manual, chapter 'Triggers' section 'Introduction to triggers' title 'Basic Trigger Events'; the 2nd table shows which different 'Event' can be combined with each different 'Level'. (Bug: I don't think there is an Object-Open trigger).

Above that we see that a 'save' event trigger means 'write' or 'modify', it does not mean 'save the module'.

So you can have a post-attribute-save trigger, which fires after the value has been changed; or a pre-module-close trigger, which figures to examine History of the current session and generate an email for all the important changes just made.

You almost certainly do NOT want to use that $include statement, since the person running DOORS may no have access to your file. Instead you should use readfile() and also checkDXL().

  • Louie

Re: Monitor the update of objects with a trigger
sdauphin - Thu Jul 15 11:34:51 EDT 2010

llandale - Sun Mar 28 18:50:30 EDT 2010
Triggers are not for the feint of heart.

If I had this chore, I'd write an on-demand script scheduled to run every night, which generates a single email and looks through all the modules of a Project looking for reportable changes in History. If scheduled for "12:01am" 00:00:01 you could look for History from 'yesterday'. Folks will appreciate a single email, and will tend to ignore the scores of individual emails they will get with the Trigger approach.

Also, the Trigger approach falls down when folks make a change, trigger an email, then do not save the module.

It is also weak in that the local user will end up sending the email, which can cause confusion and hassle.

Anway, as for the Trigger: its probably better to have the trigger deployed in the Project with smarts to know which modules to ignore. If you change the Trigger you change it on one place. Deploying it in each 'important' module makes the Trigger itself a little simpler, but its a bit of a nightmare when you want to make changes to the Trigger.

  • Louie

Louie,

I am very interested by the approach you describe : I would like to send an nightly email notification if a specific module has been modified. How do you "look for History from 'yesterday'", as you mentionned ? Any piece of code you would be able to share ?

Best regards,
Servanne.

Re: Monitor the update of objects with a trigger
llandale - Thu Jul 15 18:33:33 EDT 2010

sdauphin - Thu Jul 15 11:34:51 EDT 2010
Louie,

I am very interested by the approach you describe : I would like to send an nightly email notification if a specific module has been modified. How do you "look for History from 'yesterday'", as you mentionned ? Any piece of code you would be able to share ?

Best regards,
Servanne.

You would use the Windows 'scheduled task' feature that invokes a *.bat (text) file that contains the invokation of DOORS. I put mine in a folder and deny the rest of the entire world read rights, in order to protect the unencrypted passwords in the bat file. You write a 'batch' *.dxl script invoked via the '-b' DOORS command line switch.

In this case I'd schedule the task to run just after midnight.

First off, you need a function that looks at a date to determine if its 'yesterday'. This function does almost that, looks to see if it was in the last 24 hours.

const int   SecsInDay = 60*60*24
bool   WasThisYesterday(Date in_dat)
{    int    iNow  = intOf(today())
     int    iThen = infOf(in_dat)
     return(iThen + SecsInDay > iNow)
}    // end WasThisYesterday(Date)


Now, lets find out if a particular object has had a 'serious' change 'Yesterday'.

 

bool   WasChangedYesterday(Object obj)
{      // Was the Object changed yesterday?
     History   hst
     Date      datHist
     string    NameAttr
     for hst in obj do
     {  datHist = hst.date
        if (!WasThisYesterday(datHist)) continue
                // Changed yesterday.  Is it a 'serious' change?
        noError()
        NameAttr = ""
        NameAttr = hst.attrName
        lastError
        if (NameAttr == "Object Text") return(true) // Serious/recent change
     }
     return(false)
}    // end WasChangedYesterday(Object)


You would need to associated each object (or perhaps each module) with a particular distribution of people ..err.. doors users. Not sure how best to do that. You could get their valid Email address from their DOORS properties, presuming the current user has 'user' rights, and generate your emails from that.

Perhaps you want the script to read two user-maintained CSV files [1] List of modules (col 1) and which 'group' (col 2)gets notified when an object in that group changes, and [2] List of groups (col 1) and all the Emails (col 2) associated with that group; semi-colon separated.

Internally, perhaps have a Global Skip list whose 'Key' is the group names read from the file and the 'Data' is a 'Buffer' you create and store in the Skip.

Perhaps internally you create a 'Buffer' for each 'group' read from the first file. When you find an object that changed that belongs to that group, you retrieve the Buffer from the Skip list and append and EOL and the module name and object identifier. (No need to re-insert the Buffer back into the Skip, its already there). You thus accumulate a list of Objects for that Group.

After opening all the modules in your Project, find the Emails associated with that Group and create an Email. Use 'sendEmailMessage' if your database is configured for Emails. Otherwise, struggle through OLE getting a handle on the 'Outlook.exe' and 'put'ting 'methods'; something like this where 'fOleOK' is a function I wrote to traps and reports errors.

 

 

const string    gl_OleOutlookApp        = "Outlook.Application"       // Windows recognizes this as a running Outlook
 
//******************************
bool    fEmailCreateOutlookMail(bool DoSend, string SendTo, SendCC, SendBCC, Subject, Body)
{     // Create the Email message which requires that Outlook.exe is running.
        // SendTo, SendCC, and SendBCC should be valid Email addresses separated by semi-colons;.
        // Send the Message when DoSend, otherwise just display it.
 
 
        bool    Result  = false
        OleAutoObj      oaoMessage      = null
        OleAutoObj      oaoOutlook      = oleGetAutoObject(gl_OleOutlookApp)
        if (null oaoOutlook)
        {  fOleOK("Outlook not running", "GetOutlook")    // Log Error
           return(false)
        }
        OleAutoArgs     autoArgs        = create()
        clear(autoArgs)
        put(autoArgs, 0)           // 0 is Outlook's symbolic constant for mail item
 
        if(fOleOK(oleMethod(oaoOutlook, "CreateItem", autoArgs, oaoMessage), "CreateItem")  and
                fOleOK(olePut(oaoMessage, "To",      SendTo),   "To")       and
                fOleOK(olePut(oaoMessage, "CC",      SendCC),   "CC")       and
                fOleOK(olePut(oaoMessage, "BCC",     SendBCC),  "BCC")      and
                fOleOK(olePut(oaoMessage, "Subject", Subject),  "Subject")  and
                fOleOK(olePut(oaoMessage, "Body",    Body),     "Body")
          )
        {            // Message created OK. Send or just Show it
           if (DoSend)
                Result = fOleOK(oleMethod(oaoMessage, "Send"), "Send")
           else Result = fOleOK(oleMethod(oaoMessage, "Display"), "Display")
        }
        else Result = false
        delete(autoArgs)
        return(Result)
}    // end fEmailCreateOutlookMail()


Turns out this will work so long as Outlook has 'ever' run since startup, even if you close it.

Good luck.

 

 

 

  • Louie

 

 

Re: Monitor the update of objects with a trigger
sdauphin - Mon Jul 19 08:47:33 EDT 2010

llandale - Thu Jul 15 18:33:33 EDT 2010

You would use the Windows 'scheduled task' feature that invokes a *.bat (text) file that contains the invokation of DOORS. I put mine in a folder and deny the rest of the entire world read rights, in order to protect the unencrypted passwords in the bat file. You write a 'batch' *.dxl script invoked via the '-b' DOORS command line switch.

In this case I'd schedule the task to run just after midnight.

First off, you need a function that looks at a date to determine if its 'yesterday'. This function does almost that, looks to see if it was in the last 24 hours.

const int   SecsInDay = 60*60*24
bool   WasThisYesterday(Date in_dat)
{    int    iNow  = intOf(today())
     int    iThen = infOf(in_dat)
     return(iThen + SecsInDay > iNow)
}    // end WasThisYesterday(Date)


Now, lets find out if a particular object has had a 'serious' change 'Yesterday'.

 

bool   WasChangedYesterday(Object obj)
{      // Was the Object changed yesterday?
     History   hst
     Date      datHist
     string    NameAttr
     for hst in obj do
     {  datHist = hst.date
        if (!WasThisYesterday(datHist)) continue
                // Changed yesterday.  Is it a 'serious' change?
        noError()
        NameAttr = ""
        NameAttr = hst.attrName
        lastError
        if (NameAttr == "Object Text") return(true) // Serious/recent change
     }
     return(false)
}    // end WasChangedYesterday(Object)


You would need to associated each object (or perhaps each module) with a particular distribution of people ..err.. doors users. Not sure how best to do that. You could get their valid Email address from their DOORS properties, presuming the current user has 'user' rights, and generate your emails from that.

Perhaps you want the script to read two user-maintained CSV files [1] List of modules (col 1) and which 'group' (col 2)gets notified when an object in that group changes, and [2] List of groups (col 1) and all the Emails (col 2) associated with that group; semi-colon separated.

Internally, perhaps have a Global Skip list whose 'Key' is the group names read from the file and the 'Data' is a 'Buffer' you create and store in the Skip.

Perhaps internally you create a 'Buffer' for each 'group' read from the first file. When you find an object that changed that belongs to that group, you retrieve the Buffer from the Skip list and append and EOL and the module name and object identifier. (No need to re-insert the Buffer back into the Skip, its already there). You thus accumulate a list of Objects for that Group.

After opening all the modules in your Project, find the Emails associated with that Group and create an Email. Use 'sendEmailMessage' if your database is configured for Emails. Otherwise, struggle through OLE getting a handle on the 'Outlook.exe' and 'put'ting 'methods'; something like this where 'fOleOK' is a function I wrote to traps and reports errors.

 

 

const string    gl_OleOutlookApp        = "Outlook.Application"       // Windows recognizes this as a running Outlook
 
//******************************
bool    fEmailCreateOutlookMail(bool DoSend, string SendTo, SendCC, SendBCC, Subject, Body)
{     // Create the Email message which requires that Outlook.exe is running.
        // SendTo, SendCC, and SendBCC should be valid Email addresses separated by semi-colons;.
        // Send the Message when DoSend, otherwise just display it.
 
 
        bool    Result  = false
        OleAutoObj      oaoMessage      = null
        OleAutoObj      oaoOutlook      = oleGetAutoObject(gl_OleOutlookApp)
        if (null oaoOutlook)
        {  fOleOK("Outlook not running", "GetOutlook")    // Log Error
           return(false)
        }
        OleAutoArgs     autoArgs        = create()
        clear(autoArgs)
        put(autoArgs, 0)           // 0 is Outlook's symbolic constant for mail item
 
        if(fOleOK(oleMethod(oaoOutlook, "CreateItem", autoArgs, oaoMessage), "CreateItem")  and
                fOleOK(olePut(oaoMessage, "To",      SendTo),   "To")       and
                fOleOK(olePut(oaoMessage, "CC",      SendCC),   "CC")       and
                fOleOK(olePut(oaoMessage, "BCC",     SendBCC),  "BCC")      and
                fOleOK(olePut(oaoMessage, "Subject", Subject),  "Subject")  and
                fOleOK(olePut(oaoMessage, "Body",    Body),     "Body")
          )
        {            // Message created OK. Send or just Show it
           if (DoSend)
                Result = fOleOK(oleMethod(oaoMessage, "Send"), "Send")
           else Result = fOleOK(oleMethod(oaoMessage, "Display"), "Display")
        }
        else Result = false
        delete(autoArgs)
        return(Result)
}    // end fEmailCreateOutlookMail()


Turns out this will work so long as Outlook has 'ever' run since startup, even if you close it.

Good luck.

 

 

 

  • Louie

 

 

Thank you , Louie ! That was an extensive and very useful answer.

Thanks to your code snippets, I implemented a quick solution. I just check the last modified date of the modules, and send an email to a (hard coded) list of people.

From what you are describing, I need to think more about how I am going to manage users and email lists in the long run ...

Frankly speaking, I am a little surprized that we need to code everything to deploy email notifications. From a long-standing tool like DOORS, I would expect something more user-friendly.

Best regards,
Servanne.

Re: Monitor the update of objects with a trigger
llandale - Mon Jul 19 11:13:09 EDT 2010

sdauphin - Mon Jul 19 08:47:33 EDT 2010
Thank you , Louie ! That was an extensive and very useful answer.

Thanks to your code snippets, I implemented a quick solution. I just check the last modified date of the modules, and send an email to a (hard coded) list of people.

From what you are describing, I need to think more about how I am going to manage users and email lists in the long run ...

Frankly speaking, I am a little surprized that we need to code everything to deploy email notifications. From a long-standing tool like DOORS, I would expect something more user-friendly.

Best regards,
Servanne.

Like I said, that function is for when you have NOT got your database configured for Email. If you do, use the sendEMailMessage functions.